意外と妙なところでハードルが高かったのでメモ。
Windows ストア アプリにおいて、XML形式でのシリアライズとデシリアライズ。
using System.Xml;
using System.Runtime.Serialization;
……
[DataContract]
class X
{
[DataMember]
public string s1;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var x = new X();
x.s1 = "TestData";
var ds = new DataContractSerializer(typeof(X));
using (TextWriter sw = new StringWriter())
{
using (var xw = XmlWriter.Create(sw))
{
ds.WriteObject(xw, x);
}
TextBlock1.Text = sw.ToString();
}
using (TextReader sw = new StringReader(TextBlock1.Text))
{
using (var xw = XmlReader.Create(sw))
{
X o = (X)ds.ReadObject(xw, false);
TextBlock2.Text = o.s1;
}
}
}
意外と引っかかるのはWriteObject, ReadObjectメソッドがXmlReader, XmlWriterオブジェクトを要求すること。このクラスは抽象クラスだからnewできないので、通常はXmlTextReaderやXmlTextWriter(等)をnewするわけですが、Windows ストア アプリではnewできません。しかし、F1を押すと.NET Framework 4.5のリファレンスに飛んで、XmlTextReader/Writerを受け付けると読めてしまいます。結局、このジレンマを解消するには.NET Framework 2.0以降存在する昔ながらのCreateメソッドの利用というわけです。
しかし、これが吐き出すXMLはプロジェクト依存です。プロジェクト名クラス名が埋め込まれてしまっています。アプリ間連携に使いにくい中身です。
<?xml version="1.0" encoding="utf-16"?><MainPage.X xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/SerializeInWindowsStoreApp001"><s1>TestData</s1></MainPage.X>
依存性のある情報は取ってしまえ §
というわけで、プロジェクト名とクラス名を取ってみました。
[DataContract(Namespace = "")]
class Y
{
[DataMember]
public string s1;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
var y = new Y();
y.s1 = "TestData";
var ds = new DataContractSerializer(typeof(Y), "root", "");
using (TextWriter sw = new StringWriter())
{
using (var xw = XmlWriter.Create(sw))
{
ds.WriteObject(xw, y);
}
TextBlock1.Text = sw.ToString();
}
using (TextReader sw = new StringReader(TextBlock1.Text))
{
using (var xw = XmlReader.Create(sw))
{
Y o = (Y)ds.ReadObject(xw, false);
TextBlock2.Text = o.s1;
}
}
}
これで実行結果は以下のようになります。メンバーの名前は見えてもそれはいいかな。(これも、属性で変更できる)
<?xml version="1.0" encoding="utf-16"?><root xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><s1>TestData</s1></root>
補足 §
ちなみに、Createメソッドが返すのは以下の2つの非公開クラスのオブジェクトらしい。
- System.Xml.XmlWellformedWriter
- System.Xml.XmlTextReaderImpl
XmlTextReaderやXmlTextWriterがなくても、これがあれば十分ということらしい。これらが見えなくても、抽象クラスのXmlReader/Writerが見えるのでそれ経由でアクセスできるから良いということかな?
ちなみに、上の2クラスはWindows ストア アプリで初めて導入されたものではなく、昔からあったらしい。(ドキュメントに載っていないだけで)